﻿var _CRUD = (function () {
    var disabledPages = ["Read", "Delete"];

    var initialize = function (formId) {
        if (formId) {
            if (!$("#" + formId))
                throw error("Please, add 'create' form");

            if (!$("#" + formId).attr("action"))
                throw error("Please, add action to create form");
        }
    };

    var invoke = function (formId, data) {
        var action = $("#" + formId).attr("action");
        var method = $("#" + formId).attr("method");

        ui.Animation.ShowLoading();
        var request = $.ajax({
            url: action,
            type: method,
            data: ko.toJSON(data),
            cache: false,
            contentType: 'application/json',
            dataType: "json"
        });

        return request;
    };

    var messageWithAction = function (options) {
        var message = "";
        var actions = options.Actions ? options.Actions : [];

        for (var i in actions) {
            var action = actions[i];
            message += "<button class='" + action.CssClass + "' id='action_" + i + "'><span><b>" + action.Text + "</b></span></button>";
        }

        return message;
    };

    var messageWithActionBehavior = function (options) {
        var actions = options.Actions ? options.Actions : [];

        for (var i in actions) {
            var action = actions[i];

            $("#action_" + i).bind("click", { action: action }, function (event) {
                event.data.action.Behavior();
            });
        }
    };

    return {
        PrepareViewModel: function (viewModel) {
            viewModel.EmptyEntity = ko.toJS(viewModel.Entity);
            viewModel.SelectedItem = ko.observable();

            viewModel.SelectItem = function (action, item) {
                viewModel.SelectedItem(item);

                Main.Page.ChangeHash(action + "/" + item.Id());
            };

            viewModel.RebindList = function () {
                var method = whoever.AJAX.Method({
                    data: {},
                    action: "/" + Main.State.CurrentController() + "/RebindList"
                });

                method.success(function (List) {
                    ko.mapping.fromJS(List, {}, viewModel.List);
                });
            };

            viewModel.Create = function () {
                if (Main.Validation.ModelIsValid(viewModel.Entity)) {
                    var method = Main.CRUD.Create(viewModel.Entity);

                    method.success(function (result) {
                        viewModel.RebindList();

                        ui.Animation.HideLoading(function () {
                            var options = [];

                            options.Actions = [
                                { Text: "Crear otro", CssClass: result.Success ? "btn btn-success" : "btn btn-warning", Behavior: Main.CRUD.ResetForm },
                                { Text: "Volver", CssClass: "btn btn-default", Behavior: function () { Main.Page.ChangeHash("Info"); } }
                            ];

                            options.MessageType = result.MessageType;
                            options.Message = result.Message;

                            Main.CRUD.MessageWithAction(options);

                            whoever.Form.EnableBack();
                        });
                    });

                    method.error(function () {
                        ui.Animation.HideLoading(ui.Message.Error(errorMessage));
                    });
                }
            };

            viewModel.Update = function () {
                if (Main.Validation.ModelIsValid(viewModel.SelectedItem())) {
                    var method = Main.CRUD.Update(viewModel.SelectedItem());

                    method.success(function (result) {
                        ui.Animation.HideLoading(function () {
                            var options = [];

                            options.Actions = [
                                { Text: "Seguir editando", CssClass: result.Success ? "btn btn-success" : "btn btn-warning", Behavior: whoever.Form.EnableAll },
                                { Text: "Volver", CssClass: "btn btn-default", Behavior: function () { Main.Page.ChangeHash("Info"); } }
                            ];

                            options.MessageType = result.MessageType;
                            options.Message = result.Message;

                            Main.CRUD.MessageWithAction(options);

                            whoever.Form.EnableBack();
                        });
                    });

                    method.error(function () {
                        ui.Animation.HideLoading(ui.Message.Error(errorMessage));
                    });
                }
            };

            viewModel.Delete = function () {
                if (Main.Validation.ModelIsValid(viewModel.SelectedItem())) {
                    var method = Main.CRUD.Delete(viewModel.SelectedItem());

                    method.success(function (result) {
                        viewModel.RebindList();

                        ui.Animation.HideLoading(function () {
                            var options = [];

                            options.Actions = [
                                { Text: "Volver", CssClass: "btn btn-default", Behavior: function () { Main.Page.ChangeHash("Info"); } }
                            ];

                            options.MessageType = result.MessageType;
                            options.Message = result.Message;

                            Main.CRUD.MessageWithAction(options);

                            whoever.Form.EnableBack();
                        });
                    });

                    method.error(function () {
                        ui.Animation.HideLoading(ui.Message.Error(errorMessage));
                    });
                }
            };
        },
        Init: function (viewModel, startPage, controller) {
            Main.State.IsCRUD(true);

            Main.State.Hashes.push("Create");
            Main.State.Hashes.push("Read");
            Main.State.Hashes.push("Update");
            Main.State.Hashes.push("Delete");

            Main.Page.Init(startPage, controller);

            if (Main.State.TryIndexing())
                Main.CRUD.LoadIndexed(viewModel, Main.State.IndexedId());

            ui.Form.FormEnabling(Main.State.CurrentPage(), disabledPages);

            Main.State.CurrentPage.subscribe(function (newPage) {
                ui.Form.FormEnabling(newPage, disabledPages);

                if (newPage == "Create")
                    Main.CRUD.ResetForm();
            });
        },
        Create: function (data) {
            initialize("create");
            return invoke("create", data);
        },
        Read: function () {

        },
        Update: function (data) {
            initialize("update");
            return invoke("update", data);
        },
        Delete: function (data) {
            initialize("delete");
            return invoke("delete", data);
        },
        LoadIndexed: function (viewModel, id) {
            if (!viewModel.SelectedItem) console.error("SelectedItem is required");
            if (!viewModel.List) console.error("List is required");

            var item = whoever.Observables.GetBy(viewModel.List(), "Id", id)[0]

            if (viewModel.SelectItem)
                viewModel.SelectItem(Main.State.CurrentPage(), item);
            else
                viewModel.SelectedItem(item);
        },
        ResetForm: function () {
            ko.mapping.fromJS(viewModel.EmptyEntity, {}, viewModel.Entity);
            whoever.Form.EnableAll();
        },
        MessageWithAction: function (options) {
            switch (options.MessageType) {
                case 0:
                    Main.CRUD.InfoWithAction(options);
                    break;
                case 1:
                    Main.CRUD.SuccessWithAction(options);
                    break;
                case 2:
                    Main.CRUD.WarningWithAction(options);
                    break;
                case 3:
                    Main.CRUD.ErrorWithAction(options);
                    break;
                default:
                    Main.CRUD.ErrorWithAction(options);
                    break;
            }
        },
        InfoWithAction: function (options) {
            ui.Message.Info((options.Message || "Información disponible,") + " " + messageWithAction(options));
            messageWithActionBehavior(options);
        },
        SuccessWithAction: function (options) {
            ui.Message.Success((options.Message || "La operación se realizó con éxito,") + " " + messageWithAction(options));
            messageWithActionBehavior(options);
        },
        WarningWithAction: function (options) {
            ui.Message.Warning((options.Message || "La operación se realizó con errores,") + " " + messageWithAction(options));
            messageWithActionBehavior(options);
        },
        ErrorWithAction: function (options) {
            ui.Message.Error((options.Message || "La operación no se realizó con éxito,") + " " + messageWithAction(options));
            messageWithActionBehavior(options);
        },
    };
})();